package org.baicaixiaozhan.springbootwebdemo1.filter;

import com.google.common.base.Strings;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.baicaixiaozhan.springbootwebdemo1.config.JwtConfig;
import org.baicaixiaozhan.springbootwebdemo1.dao.UserDao;
import org.baicaixiaozhan.springbootwebdemo1.domain.User;
import org.baicaixiaozhan.springbootwebdemo1.domain.UserRole;
import org.baicaixiaozhan.springbootwebdemo1.exception.IllegalTokenException;
import org.baicaixiaozhan.springbootwebdemo1.exception.NotLoggedException;
import org.baicaixiaozhan.springbootwebdemo1.util.FilterUtils;
import org.baicaixiaozhan.springbootwebdemo1.util.HttpUtils;
import org.baicaixiaozhan.springbootwebdemo1.util.JWTUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.crypto.SecretKey;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 每次请求都会执行一次此 filter <br />
 * 对每次请求带过来的 token 进行解析判断
 *
 * @author baicaixiaozhan
 * @since 2021/1/29
 */
@Slf4j
@AllArgsConstructor
@Component
public class JwtResolverFilter extends OncePerRequestFilter {

    private static final String LOGIN_URI = "/api/login";
    private final JwtConfig jwtConfig;
    private final SecretKey secretKey;
    private final UserDao userDao;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        // 过滤 /login
        if (isEqualsLoginURI(request)) {
            filterChain.doFilter(request, response);
            return;
        }

        // 无 token / 非法 token 请求, 拒绝访问
        String authorization = request.getHeader("authorization");
        if (isEmptyAuthorization(authorization)) {
            FilterUtils.exceptionForward(request, response, "filter.exception",
                    new NotLoggedException("未登录, 不能访问此接口."), "/filter/exception");
            return;
        }
        if (isIllegalAuthorization(authorization)) {
            FilterUtils.exceptionForward(request, response, "filter.exception",
                    new IllegalTokenException("token 不能为空."), "/filter/exception");
            return;
        }

        String token = authorization.replace(jwtConfig.getTokenPrefix(), "");
        try {
            Claims body = JWTUtils.tokenParser(token, secretKey);
            String username = body.getSubject();
            String authorize = body.get("authorities").toString();

            // TODO 校验 用户+角色
            log.info("username: {}", username);
            log.info("authorize: {}", authorize);

            // 存入到当前 request 中
            User user = userDao.findUserByUsername(username);
            user.setUserRole(UserRole.valueOf(authorize));
            HttpUtils.setCurrentLoginUser(user);

        } catch (JwtException e) {
            FilterUtils.exceptionForward(request, response, "filter.exception",
                    new IllegalStateException("this token cannot trust"), "/filter/exception");
            return;
        }
        filterChain.doFilter(request, response);
    }

    /**
     * 是否为登录请求
     *
     * @param request
     * @return
     */
    private Boolean isEqualsLoginURI(HttpServletRequest request) {
        return LOGIN_URI.equals(request.getRequestURI());
    }

    /**
     * 是否为非法授权
     *
     * @param authorization
     * @return
     */
    private Boolean isIllegalAuthorization(String authorization) {
        return !authorization.startsWith(jwtConfig.getTokenPrefix());
    }

    /**
     * 是否为空
     *
     * @param authorization
     * @return
     */
    private Boolean isEmptyAuthorization(String authorization) {
        return Strings.isNullOrEmpty(authorization);
    }
}
